package com.nercel.dsj.gksales.shiro.realm;

import com.nercel.dsj.gksales.model.entity.Permission;
import com.nercel.dsj.gksales.model.entity.Role;
import com.nercel.dsj.gksales.model.entity.User;
import com.nercel.dsj.gksales.service.RoleService;
import com.nercel.dsj.gksales.shiro.JwtToken;
import com.nercel.dsj.gksales.shiro.exception.ExpiredJwtAuthenticationException;
import com.nercel.dsj.gksales.shiro.exception.MalformedJwtAuthenticationException;
import com.nercel.dsj.gksales.shiro.service.ShiroService;
import com.nercel.dsj.gksales.util.JwtUtil;
import io.jsonwebtoken.ExpiredJwtException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author sunlin
 * @date 2018-12-7
 */
public class JwtRealm extends AuthorizingRealm {

	private static final String REALM_NAME = "JWT_REALM";

	@Autowired
	ShiroService shiroService;

	@Autowired
	RoleService roleService;

	/**
	 *  认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
		if (!(authToken instanceof JwtToken)) {
			throw new MalformedJwtAuthenticationException();
		}
		String token  = (String) authToken.getCredentials();
		String username;
		try {
			username = JwtUtil.parseJWT(token).getSubject();
		} catch (ExpiredJwtException e) {
			throw new ExpiredJwtAuthenticationException();
		} catch (Exception e) {
			throw new MalformedJwtAuthenticationException();
		}
		return new SimpleAuthenticationInfo(username, token, REALM_NAME);
	}

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String userId = (String) principals.getPrimaryPrincipal();
		User user = shiroService.getUserById(Integer.valueOf(userId));
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		Set<String> roles = new HashSet<>();
		Set<String> permissions = new HashSet<>();
		List<Role> userRoles = roleService.selectByUserIdWithPermissions(user.getId());
		for (Role role : userRoles) {
			roles.add(role.getRole());
			for (Permission permission : role.getPermissions()) {
				permissions.add(permission.getPermission());
			}
		}
		simpleAuthorizationInfo.setRoles(roles);
		simpleAuthorizationInfo.setStringPermissions(permissions);
		return simpleAuthorizationInfo;
	}

	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof JwtToken;
	}

}
